package com.pig4cloud.pig.common.swagger.plugins;

import cn.hutool.core.lang.Pair;
import com.bblocks.config.SwaggerDisplayEnum;
import com.pig4cloud.pig.common.swagger.support.EnumPluginUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.schema.ScalarType;
import springfox.documentation.service.AllowableListValues;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.ParameterBuilderPlugin;
import springfox.documentation.spi.service.contexts.ParameterContext;

import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>Project: bblocks-pro - EnumParameterBuilderPlugin</p>
 * <p>描述：枚举支持(路径参数或者表单形式)</p>
 *
 * @Author Zhao [125043150@qq.com]
 * @Date 2024/3/1 17:13
 * @Version 1.0
 * @since 8
 */
@Order
@Component
public class EnumParameterBuilderPlugin implements ParameterBuilderPlugin {

    @Override
    public void apply(ParameterContext context) {
        Class<?> type = context.resolvedMethodParameter().getParameterType().getErasedType();
        if (Enum.class.isAssignableFrom(type)) {
            SwaggerDisplayEnum annotation = AnnotationUtils.findAnnotation(type, SwaggerDisplayEnum.class);
            if (annotation != null) {
                Object[] enumConstants = type.getEnumConstants();
                List<Pair<Object,String>> enumKeyValues = EnumPluginUtils.getEnumKeyValues(enumConstants, annotation);
                List<String> displayValues = enumKeyValues.stream().map(tuple -> tuple.getKey().toString()).collect(Collectors.toList());
                List<String> keyValues = enumKeyValues.stream().map(tuple -> tuple.getKey() + "-" + tuple.getValue()).collect(Collectors.toList());
                RequestParameterBuilder requestParameterBuilder = context.requestParameterBuilder();
                String description;
                try {
                    Field descField = RequestParameterBuilder.class.getDeclaredField("description");
                    descField.setAccessible(true);
                    description = descField.get(requestParameterBuilder) + "(" + String.join("; ", keyValues) + ")";
                } catch (IllegalAccessException | NoSuchFieldException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }

                Pair<ScalarType,String> valueType = EnumPluginUtils.getValueType(enumKeyValues.get(0).getKey());
                requestParameterBuilder.description(description);
                requestParameterBuilder.query(simpleParameterSpecificationBuilder -> simpleParameterSpecificationBuilder
                        .model(modelSpecificationBuilde -> modelSpecificationBuilde.scalarModel(valueType.getKey()))
                        .enumerationFacet(enumerationElementFacetBuilder -> enumerationElementFacetBuilder.allowedValues(new AllowableListValues(displayValues, valueType.getValue())))
                );
            }
        }
    }

    @Override
    public boolean supports(DocumentationType documentationType) {
        return true;
    }
}
